/**
 * Copyright (c) 2023 murenchao
 * taomu is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.box.guice.util

import com.google.inject.Binder
import com.google.inject.Key
import com.google.inject.Scopes
import com.google.inject.name.Names
import cool.taomu.box.asm.CreateClass
import cool.taomu.box.asm.entity.ClassEntity
import java.util.List
import java.util.Map
import java.util.Properties
import java.util.UUID
import javax.inject.Provider
import org.apache.commons.lang3.StringUtils
import org.objectweb.asm.Type
import org.yaml.snakeyaml.Yaml

class TaomuNames {

	private new() {
	}

	def static named(String name) {
		return Names.named(name);
	}

	def static void bindProperties(Binder binder, Map<String, String> properties) {
		Names.bindProperties(binder, properties);
	}

	def static void bindProperties(Binder binder, Properties properties) {
		Names.bindProperties(binder, properties);
	}

	static class Covert {
		def dispatch bind(Binder binder, String ns, Integer o) {
			binder.bind(Key.get(Integer, Names.named(ns))).toInstance(o);
		}

		def dispatch bind(Binder binder, String ns, String o) {
			binder.bind(Key.get(String, Names.named(ns))).toInstance(o);
		}

		def dispatch bind(Binder binder, String ns, Double o) {
			binder.bind(Key.get(Double, Names.named(ns))).toInstance(o);
		}

		def dispatch bind(Binder binder, String ns, Float o) {
			binder.bind(Key.get(Float, Names.named(ns))).toInstance(o);
		}

		def dispatch bind(Binder binder, String ns, List<Map<String, Object>> o) {
			binder.bind(Key.get(List, Names.named(ns))).toInstance(o);
		}

	}

	def static covertYaml(Binder binder, Map<String, Object> yml) {
		yml.forEach [ k, v |
			if (v instanceof Map) {
				covertChildYaml(binder, k, v);
			} else {
				new Covert().bind(binder, k, v)
			}
		]
	}

	def static void covertChildYaml(Binder binder, String namespace, Map<String, Object> yml) {
		yml.forEach [ k, v |
			var ns = StringUtils.isNotBlank(k) ? #[namespace, k].join(".") : k;
			if (v instanceof Map) {
				covertChildYaml(binder, ns, yml)
			} else {
				new Covert().bind(binder, ns, v)
			}
		]
	}

	def static void bindYaml(Binder binder, String path) {
		var binder2 = binder.skipSources(Names);
		var yml = new Yaml()
		var map = yml.loadAs(TaomuResource.read(path), Map) as Map<String, Object>
		covertYaml(binder2, map);
	}

	def static <T> void bindYaml(Binder binder, String path, Class<T> zlass) {
		var name = UUID.randomUUID.toString.replace("-", "");
		var moduleName = #["Taomu", name, "BaseModule"].join("");
		var classEntity = new ClassEntity("cool.taomu.box", moduleName);
		classEntity.superclass = Type.getType(zlass).internalName;
		var cc = CreateClass.Class(classEntity);
		cc.constructor(zlass.constructors)
		cc.end();
		var nclass = cc.loadClass(#["cool.taomu.box",moduleName].join(".")) as Class<T>;
		binder.bind(nclass).toProvider(new Provider<T>() {
			override get() {
				var yml = new Yaml()
				var t = yml.loadAs(TaomuResource.read(path), zlass);
				return t;
			}
		})

		binder.bind(zlass).to(nclass).in(Scopes.SINGLETON)
	}
}
